/**
 * WebGL渲染器类，负责将Scene中的图元渲染为WebGL图形，支持完整渲染和增量渲染
 */

import { Scene, PrimitiveType, Primitive, Layer } from './scene';

// 添加一个简单的工具函数，用于在浏览器控制台打印日志
function log(...args: any[]) {
  if (typeof console !== 'undefined') {
    console.log('[WebGLRenderer]', ...args);
  }
}

/**
 * WebGL渲染器选项
 */
export interface WebGLRendererOptions {
  document?: Document;
  canvas?: HTMLCanvasElement;
}

/**
   * WebGL渲染器类
   */
export class WebGLRenderer {
  private document: Document;
  private canvas: HTMLCanvasElement;
  private gl: WebGLRenderingContext | null;
  private currentScene: Scene | null = null;
  private primitiveBuffers: Map<string, WebGLBuffer> = new Map();
  private primitivePrograms: Map<string, WebGLProgram> = new Map();
  
  constructor(options: WebGLRendererOptions = {}) {
    this.document = options.document || (typeof document !== 'undefined' ? document : ({} as Document));
    this.canvas = options.canvas || this.document.createElement('canvas');
    this.gl = this.canvas.getContext('webgl');
    
    if (!this.gl) {
      console.error('[WebGLRenderer] WebGL is not supported in this browser');
    }
    
    // 设置canvas样式
    this.canvas.className = 'gpui-webgl-canvas';
    this.canvas.style.position = 'relative';
    this.canvas.style.width = '100%';
    this.canvas.style.height = '100%';
    this.canvas.style.display = 'block';
    
    // 绑定canvas点击事件
    this.canvas.addEventListener('click', this.handleCanvasClick.bind(this));
    
    // 初始化资源映射
    this.primitiveBuffers = new Map();
    this.primitivePrograms = new Map();
  }

  /**
   * 将Scene渲染为WebGL画布（完整渲染）
   */
  renderScene(scene: Scene): HTMLCanvasElement {
    log('renderScene: 开始渲染Scene');
    
    if (!this.gl) {
      console.error('[WebGLRenderer] No WebGL context available');
      return this.canvas;
    }
    
    // 保存当前场景引用，用于事件处理
    this.currentScene = scene;
    
    // 获取容器尺寸
    const container = this.document.createElement('div');
    container.style.width = '100%';
    container.style.height = '100%';
    container.style.position = 'absolute';
    
    // 临时添加到文档以获取准确尺寸
    this.document.body.appendChild(container);
    const rect = container.getBoundingClientRect();
    this.document.body.removeChild(container);
    
    // 设置canvas尺寸
    this.canvas.width = rect.width * window.devicePixelRatio;
    this.canvas.height = rect.height * window.devicePixelRatio;
    this.canvas.style.width = `${rect.width}px`;
    this.canvas.style.height = `${rect.height}px`;
    
    // 清空画布
    this.gl.clearColor(0, 0, 0, 0);
    this.gl.clear(this.gl.COLOR_BUFFER_BIT | this.gl.DEPTH_BUFFER_BIT);
    
    // 重置资源映射
    this.resetResources();
    
    // 设置视口
    this.gl.viewport(0, 0, this.canvas.width, this.canvas.height);
    
    // 按图层顺序渲染
    const layers = scene.getLayers();
    log('renderScene: 图层数量:', layers.length);
    
    layers.forEach(layer => {
      log('renderScene: 渲染图层:', layer.id, '图元数量:', layer.primitives.length);
      this.renderLayer(layer);
    });
    
    log('renderScene: Scene渲染完成');
    return this.canvas;
  }
  
  /**
   * 更新现有Scene的WebGL渲染（增量渲染）
   */
  updateScene(scene: Scene): boolean {
    log('updateScene: 开始更新Scene');
    
    if (!this.gl) {
      console.error('[WebGLRenderer] No WebGL context available');
      return false;
    }
    
    // 保存当前场景引用
    this.currentScene = scene;
    
    // 检查是否有任何更新
    if (!scene.hasUpdates()) {
      log('updateScene: 没有需要更新的内容');
      return false;
    }
    
    // 获取更新和删除的图元
    const updatedPrimitives = scene.getUpdatedPrimitives();
    const removedPrimitives = scene.getRemovedPrimitives();
    
    log('updateScene: 更新的图元数量:', updatedPrimitives.size);
    log('updateScene: 删除的图元数量:', removedPrimitives.size);
    
    // 对于WebGL渲染器，我们需要重新绘制整个场景，因为WebGL没有简单的部分更新机制
    // 但是我们可以优化资源管理
    
    // 清理被删除图元的资源
    removedPrimitives.forEach(id => {
      this.cleanupPrimitiveResources(id);
    });
    
    // 清空画布（对于WebGL，我们需要重绘整个场景）
    if (!this.gl) return false;
    
    this.gl.clearColor(0, 0, 0, 0);
    this.gl.clear(this.gl.COLOR_BUFFER_BIT | this.gl.DEPTH_BUFFER_BIT);
    
    // 按图层顺序渲染更新的内容
    const layers = scene.getLayers();
    
    layers.forEach(layer => {
      // 只渲染更新的图元和新添加的图元
      layer.primitives.forEach(primitive => {
        if (updatedPrimitives.has(primitive.id)) {
          log('updateScene: 渲染更新的图元:', primitive.id);
          this.renderPrimitive(primitive);
        }
      });
    });
    
    // 重置更新标记
    scene.resetUpdateMarkers();
    
    log('updateScene: Scene更新完成');
    return true;
  }
  
  /**
   * 清理图元资源
   */
  private cleanupPrimitiveResources(id: string): void {
    if (!this.gl) return;
    
    // 删除缓冲区
    if (this.primitiveBuffers.has(id)) {
      const buffer = this.primitiveBuffers.get(id);
      if (buffer) {
        this.gl.deleteBuffer(buffer);
        this.primitiveBuffers.delete(id);
      }
    }
    
    // 删除着色器程序（注意：通常不应该为每个图元创建单独的程序）
    if (this.primitivePrograms.has(id)) {
      const program = this.primitivePrograms.get(id);
      if (program) {
        this.gl.deleteProgram(program);
        this.primitivePrograms.delete(id);
      }
    }
  }
  
  /**
   * 重置所有资源
   */
  private resetResources(): void {
    if (!this.gl) return;
    
    const gl = this.gl;
    
    // 删除所有缓冲区
    this.primitiveBuffers.forEach(buffer => {
      if (buffer) {
        gl.deleteBuffer(buffer);
      }
    });
    this.primitiveBuffers.clear();
    
    // 删除所有着色器程序
    this.primitivePrograms.forEach(program => {
      if (program) {
        gl.deleteProgram(program);
      }
    });
    this.primitivePrograms.clear();
  }
  
  /**
   * 处理canvas点击事件
   */
  private handleCanvasClick(event: MouseEvent): void {
    if (!this.currentScene) {
      return;
    }
    
    // 获取canvas上的点击坐标
    const rect = this.canvas.getBoundingClientRect();
    const x = event.clientX - rect.left;
    const y = event.clientY - rect.top;
    
    log('handleCanvasClick: 点击坐标:', x, y);
    
    // 从后往前遍历所有图层中的所有图元，找到被点击的图元
    const layers = this.currentScene.getLayers();
    for (let i = layers.length - 1; i >= 0; i--) {
      const layer = layers[i];
      for (let j = layer.primitives.length - 1; j >= 0; j--) {
        const primitive = layer.primitives[j];
        const primitiveObj = primitive as any;
        
        // 检查点击是否在图元范围内
        if (primitive.bounds && this.isPointInBounds(x, y, primitive.bounds)) {
          log('handleCanvasClick: 点击了图元:', primitive.id, '类型:', primitive.type);
          
          // 对于组件类型的图元，我们需要特殊处理
          if (primitive.type === PrimitiveType.COMPONENT && primitiveObj.data && typeof primitiveObj.data === 'object') {
            // 尝试调用组件的点击事件处理函数
            if (primitiveObj.data.onClick) {
              log('handleCanvasClick: 调用组件的onClick方法');
              primitiveObj.data.onClick();
            }
          }
          
          // 对于其他类型的图元，我们可以在这里添加相应的事件处理逻辑
          return;
        }
      }
    }
  }
  
  /**
   * 检查点是否在边界内
   */
  private isPointInBounds(x: number, y: number, bounds: { x: number, y: number, width: number, height: number }): boolean {
    return x >= bounds.x && 
           x <= bounds.x + bounds.width && 
           y >= bounds.y && 
           y <= bounds.y + bounds.height;
  }

  /**
   * 渲染图层
   */
  private renderLayer(layer: Layer): void {
    if (!this.gl) return;

    // WebGL没有save/restore方法，需要手动管理状态
    // 保存当前的着色器程序和其他状态
    const currentProgram = this.gl.getParameter(this.gl.CURRENT_PROGRAM);
    
    // 应用图层透明度需要在每个图元的着色器中处理
    // 在这个简化实现中，我们忽略全局透明度
    
    // 渲染图层中的所有图元
    layer.primitives.forEach(primitive => {
      this.renderPrimitive(primitive);
    });
    
    // 恢复之前的着色器程序
    if (currentProgram) {
      this.gl.useProgram(currentProgram as WebGLProgram);
    }
  }

  /**
   * 渲染图元
   */
  private renderPrimitive(primitive: Primitive): void {
    if (!this.gl) return;
    
    switch (primitive.type) {
      case PrimitiveType.RECT:
        this.renderRect(primitive);
        break;
      case PrimitiveType.TEXT:
        this.renderText(primitive);
        break;
      case PrimitiveType.COMPONENT:
        this.renderComponent(primitive);
        break;
      case PrimitiveType.GROUP:
        this.renderGroup(primitive);
        break;
      default:
        // 默认忽略未知类型
        break;
    }
  }

  /**
   * 渲染矩形图元
   */
  private renderRect(primitive: Primitive): void {
    if (!this.gl || !primitive.bounds) return;
    
    // 获取或创建图元的缓冲
    let positionBuffer = this.primitiveBuffers.get(primitive.id);
    if (!positionBuffer) {
      positionBuffer = this.gl.createBuffer();
      this.primitiveBuffers.set(primitive.id, positionBuffer);
    }
    
    // 绑定缓冲
    this.gl.bindBuffer(this.gl.ARRAY_BUFFER, positionBuffer);
    
    // 设置顶点数据
    const { x, y, width, height } = primitive.bounds;
    const vertices = [
      x, y,
      x + width, y,
      x, y + height,
      x + width, y + height,
    ];
    
    this.gl.bufferData(this.gl.ARRAY_BUFFER, new Float32Array(vertices), this.gl.STATIC_DRAW);
    
    // 为增量渲染优化：复用着色器程序
    let program: WebGLProgram | null | undefined = this.primitivePrograms.get('rectProgram');
    if (!program) {
      // 创建简单的着色器程序
      const vertexShaderSource = `
        attribute vec2 a_position;
        uniform vec2 u_resolution;
        void main() {
          // 从像素空间转换到裁剪空间
          vec2 zeroToOne = a_position / u_resolution;
          vec2 zeroToTwo = zeroToOne * 2.0;
          vec2 clipSpace = zeroToTwo - 1.0;
          gl_Position = vec4(clipSpace * vec2(1, -1), 0, 1);
        }
      `;
      
      const fragmentShaderSource = `
        precision mediump float;
        uniform vec4 u_color;
        void main() {
          gl_FragColor = u_color;
        }
      `;
      
      // 创建着色器
      const vertexShader = this.createShader(this.gl.VERTEX_SHADER, vertexShaderSource);
      const fragmentShader = this.createShader(this.gl.FRAGMENT_SHADER, fragmentShaderSource);
      
      // 创建程序
      program = this.createProgram(vertexShader, fragmentShader);
      
      if (!program) return;
      
      // 存储程序以便复用
      this.primitivePrograms.set('rectProgram', program);
    }
    
    // 使用程序
    this.gl.useProgram(program);
    
    // 获取attribute和uniform位置
    const positionAttributeLocation = this.gl.getAttribLocation(program, "a_position");
    const resolutionUniformLocation = this.gl.getUniformLocation(program, "u_resolution");
    const colorUniformLocation = this.gl.getUniformLocation(program, "u_color");
    
    // 启用attribute
    this.gl.enableVertexAttribArray(positionAttributeLocation);
    
    // 设置attribute格式
    this.gl.vertexAttribPointer(positionAttributeLocation, 2, this.gl.FLOAT, false, 0, 0);
    
    // 设置uniforms
    this.gl.uniform2f(resolutionUniformLocation, this.canvas.width, this.canvas.height);
    
    // 设置颜色
    let color = [0.5, 0.5, 0.5, 1.0]; // 默认灰色
    if (primitive.properties) {
      // 尝试从属性中获取颜色
      if (primitive.properties.backgroundColor) {
        // 简化处理，实际项目中可能需要解析CSS颜色字符串
        const bgColor = primitive.properties.backgroundColor.toString();
        // 这里仅处理简单的颜色格式，如'rgb(r,g,b)'或'#hex'
        if (bgColor.startsWith('rgb')) {
          const match = bgColor.match(/\d+/g);
          if (match && match.length >= 3) {
            color = [
              parseInt(match[0]) / 255,
              parseInt(match[1]) / 255,
              parseInt(match[2]) / 255,
              1.0
            ];
          }
        }
      }
    }
    
    this.gl.uniform4f(colorUniformLocation, color[0], color[1], color[2], color[3]);
    
    // 绘制矩形（两个三角形）
    this.gl.drawArrays(this.gl.TRIANGLE_STRIP, 0, 4);
  }

  /**
   * 渲染文本图元
   */
  private renderText(primitive: Primitive): void {
    if (!this.gl || !primitive.bounds) return;
    
    // WebGL渲染文本比较复杂，这里采用一种简单的方法：
    // 1. 创建一个离屏canvas
    // 2. 在离屏canvas上绘制文本
    // 3. 将离屏canvas作为纹理绘制到WebGL上下文
    
    const offscreenCanvas = this.document.createElement('canvas');
    const offscreenCtx = offscreenCanvas.getContext('2d');
    
    if (!offscreenCtx) return;
    
    const { width, height } = primitive.bounds;
  const text = primitive.properties?.text?.toString() || '';
    
    // 设置离屏canvas尺寸
    offscreenCanvas.width = width * window.devicePixelRatio;
    offscreenCanvas.height = height * window.devicePixelRatio;
    
    // 设置样式
    offscreenCtx.font = primitive.properties?.font || '16px Arial';
    offscreenCtx.fillStyle = primitive.properties?.color || 'black';
    offscreenCtx.textAlign = primitive.properties?.textAlign as CanvasTextAlign || 'left';
    offscreenCtx.textBaseline = primitive.properties?.textBaseline as CanvasTextBaseline || 'top';
    
    // 绘制文本
    offscreenCtx.fillText(text, 0, 0);
    
    // 这里应该实现将离屏canvas作为纹理绘制到WebGL的逻辑
    // 为简化示例，此处省略具体实现
  }

  /**
   * 渲染组件图元
   */
  private renderComponent(primitive: Primitive): void {
    if (!this.gl || !primitive.bounds) return;
    
    // 组件渲染逻辑
    // 在WebGL渲染器中，我们可能需要特殊处理组件
    // 这里简化处理，绘制一个占位矩形
    
    const { x, y, width, height } = primitive.bounds;
    
    // 绘制一个带有透明度的灰色矩形作为组件占位符
    const vertexShaderSource = `
      attribute vec2 a_position;
      uniform vec2 u_resolution;
      void main() {
        vec2 zeroToOne = a_position / u_resolution;
        vec2 zeroToTwo = zeroToOne * 2.0;
        vec2 clipSpace = zeroToTwo - 1.0;
        gl_Position = vec4(clipSpace * vec2(1, -1), 0, 1);
      }
    `;
    
    const fragmentShaderSource = `
      precision mediump float;
      void main() {
        gl_FragColor = vec4(0.8, 0.8, 0.8, 0.5);
      }
    `;
    
    // 创建并使用着色器程序
    const vertexShader = this.createShader(this.gl.VERTEX_SHADER, vertexShaderSource);
    const fragmentShader = this.createShader(this.gl.FRAGMENT_SHADER, fragmentShaderSource);
    const program = this.createProgram(vertexShader, fragmentShader);
    
    if (!program || !this.gl) return;
    
    this.gl.useProgram(program);
    
    // 设置顶点数据和绘制（与矩形类似）
    const positionAttributeLocation = this.gl.getAttribLocation(program, "a_position");
    const resolutionUniformLocation = this.gl.getUniformLocation(program, "u_resolution");
    
    const positionBuffer = this.gl.createBuffer();
    if (!positionBuffer) return;
    
    this.gl.bindBuffer(this.gl.ARRAY_BUFFER, positionBuffer);
    
    const vertices = [
      x, y,
      x + width, y,
      x, y + height,
      x + width, y + height,
    ];
    
    this.gl.bufferData(this.gl.ARRAY_BUFFER, new Float32Array(vertices), this.gl.STATIC_DRAW);
    this.gl.enableVertexAttribArray(positionAttributeLocation);
    this.gl.vertexAttribPointer(positionAttributeLocation, 2, this.gl.FLOAT, false, 0, 0);
    
    this.gl.uniform2f(resolutionUniformLocation, this.canvas.width, this.canvas.height);
    this.gl.drawArrays(this.gl.TRIANGLE_STRIP, 0, 4);
  }

  /**
   * 渲染组图元
   */
  private renderGroup(primitive: Primitive): void {
    if (!this.gl) return;
    
    // WebGL没有save/restore方法，需要手动管理状态
    // 在这个简化实现中，我们直接渲染子元素
    
    // 应用变换（如果有）
    if (primitive.properties?.transform) {
      // 简化处理，实际项目中可能需要更复杂的变换处理
    }
    
    // 渲染子元素
    if (primitive.children) {
      primitive.children.forEach(child => {
        this.renderPrimitive(child);
      });
    }
  }

  /**
   * 创建着色器
   */
  private createShader(type: number, source: string): WebGLShader | null {
    if (!this.gl) return null;
    
    const shader = this.gl.createShader(type);
    if (!shader) return null;
    
    this.gl.shaderSource(shader, source);
    this.gl.compileShader(shader);
    
    const success = this.gl.getShaderParameter(shader, this.gl.COMPILE_STATUS);
    if (success) {
      return shader;
    }
    
    console.error('Shader compilation error:', this.gl.getShaderInfoLog(shader));
    this.gl.deleteShader(shader);
    return null;
  }

  /**
   * 创建着色器程序
   */
  private createProgram(vertexShader: WebGLShader | null, fragmentShader: WebGLShader | null): WebGLProgram | null {
    if (!this.gl || !vertexShader || !fragmentShader) return null;
    
    const program = this.gl.createProgram();
    if (!program) return null;
    
    this.gl.attachShader(program, vertexShader);
    this.gl.attachShader(program, fragmentShader);
    this.gl.linkProgram(program);
    
    const success = this.gl.getProgramParameter(program, this.gl.LINK_STATUS);
    if (success) {
      return program;
    }
    
    console.error('Program linking error:', this.gl.getProgramInfoLog(program));
    this.gl.deleteProgram(program);
    return null;
  }
}